<template>
  <el-dialog
    v-dialogDrag
    :visible="isVisible"
    title="用户信息"
    :close-on-click-modal="false"
    @close="handleClose"
    @closed="handleClosed"
  >
    <el-form
      ref="formRef"
      :model="innerModel"
      :rules="rules"
      label-width="80px"
    >
      <el-col
        v-loading="isLoading"
      >
        <el-row
          :gutter="32"
        >
          <el-col
            :span="12"
          >
            <el-form-item
              label="工号"
              prop="code"
            >
              <el-input
                v-model="innerModel.code"
                placeholder="请输入工号"
                clearable
              >
              </el-input>
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
          >
            <el-form-item
              label="用户名"
              prop="name"
            >
              <el-input
                v-model="innerModel.name"
                placeholder="请输入用户名"
                clearable
              >
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row
          :gutter="32"
        >
          <el-col
            :span="12"
          >
            <el-form-item
              label="性别"
              prop="sex"
            >
              <el-radio-group
                v-model="innerModel.sex"
              >
                <el-radio
                  :label="0"
                >
                  男
                </el-radio>
                <el-radio
                  :label="1"
                >
                  女
                </el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
          >
            <el-form-item
              label="密码"
              prop="password"
            >
              <el-input
                v-model="innerModel.password"
                placeholder="请输入密码"
                show-password
                clearable
              >
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row
          :gutter="32"
        >
          <el-col
            :span="12"
          >
            <el-form-item
              label="所属部门"
              prop="departmentId"
            >
              <el-select
                v-model="innerModel.departmentId"
                :loading="departmentSelector.isLoading"
                class="select"
                placeholder="请选择"
                clearable
                @visible-change="handleDepartmentSelectorVisibleChange"
              >
                <el-option
                  v-for="item in departmentSelector.array"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                >
                </el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
          >
            <el-form-item
              label="职位"
              prop="positionId"
            >
              <el-select
                v-model="innerModel.positionId"
                :loading="positionSelector.isLoading"
                class="select"
                placeholder="请选择"
                clearable
                @visible-change="handlePositionSelectorVisibleChange"
              >
                <el-option
                  v-for="item in positionSelector.array"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                >
                </el-option>
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row
          :gutter="32"
        >
          <el-col
            :span="12"
          >
            <el-form-item
              label="电话"
              prop="tel"
            >
              <el-input
                v-model="innerModel.tel"
                placeholder="请输入电话"
                clearable
              >
              </el-input>
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
          >
            <el-form-item
              label="邮箱"
              prop="email"
            >
              <el-input
                v-model="innerModel.email"
                placeholder="请输入邮箱"
                clearable
              >
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row
          :gutter="32"
        >
          <el-col
            :span="12"
          >
            <el-form-item
              label="拥有角色"
              prop="roleList"
            >
              <el-select
                v-model="selectedRoleArray"
                :loading="roleSelector.isLoading"
                class="select"
                placeholder="请选择"
                multiple
                clearable
                @visible-change="handleRoleSelectorVisibleChange"
              >
                <el-option
                  v-for="item in roleSelector.array"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                >
                </el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
          >
            <el-form-item
              label="其他联系"
              prop="other"
            >
              <el-input
                v-model="innerModel.other"
                placeholder="请输入其他联系方式"
                clearable
              >
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row
          :gutter="32"
        >
          <el-col
            :span="12"
          >
            <el-form-item
              label="生日"
              prop="birthday"
            >
              <el-date-picker
                v-model="innerModel.birthday"
                class="date-picker"
                type="date"
                placeholder="选择日期"
                format="yyyy-MM-dd"
              >
              </el-date-picker>
            </el-form-item>
          </el-col>
          <el-col
            :span="12"
          >
            <el-form-item
              label="备注"
              prop="remark"
            >
              <el-input
                v-model="innerModel.remark"
                placeholder="请输入备注"
                clearable
              >
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>
      </el-col>
    </el-form>
    <div
      slot="footer"
    >
      <el-button
        @click="handleClose"
      >
        取 消
      </el-button>
      <el-button
        type="primary"
        :loading="isLoading"
        @click="handleSubmit"
      >
        提 交
      </el-button>
    </div>
  </el-dialog>
</template>

<script>
/**
 * @typedef {{
 *   'label': String,
 *   'value': String,
 * }} SelectorData
 * @typedef {{
 *   'id': String,
 * }} Role
 * @typedef {{
 *   'birthday': String,
 *   'code': String,
 *   'departmentId': String,
 *   'email': String,
 *   'name': String,
 *   'other': String,
 *   'password': String,
 *   'positionId': String,
 *   'remark': String,
 *   'roleList': Role[],
 *   'sex': null | 0 | 1,
 *   'tel': String,
 * }} Model
 */
/**
 * # 用户数据表单
 * 用于增加、修改或复制一个用户数据
 */
export default {
  'name': 'UserDataForm',

  'props': {
    /**
     * 部门选择器
     *
     * array: 用于显示在`所属部门`下拉菜单中供用户选择的数组
     *
     * isLoading: 设置选择器的加载状态
     * @type {{
     *   'array': SelectorData[],
     *   'isLoading': Boolean,
     * }}
     */
    'departmentSelector': {
      'default' () {
        return {
          'array': [],
          'isLoading': false,
        }
      },
      'type': Object,
    },
    /**
     * 设置`用户数据表单`是否为加载状态
     * @type {Boolean}
     */
    'isLoading': {
      'default': false,
      'type': Boolean,
    },
    /**
     * 设置`用户数据表单`是否为显示状态
     * @type {Boolean}
     */
    'isVisible': {
      'default': false,
      'type': Boolean,
    },
    /**
     * 从父组件传来的`用户数据表单`的数据
     *
     * 这个数据不会直接使用，而是会先复制到子组件内部中，使用副本
     * @type {Model}
     */
    'model': {
      'default' () {
        return {
          'birthday': '',
          'code': '',
          'departmentId': '',
          'email': '',
          'name': '',
          'other': '',
          'password': '',
          'positionId': '',
          'remark': '',
          'roleList': [],
          'sex': null,
          'tel': '',
        }
      },
      'type': Object,
    },
    /**
     * 职位选择器
     *
     * array: 用于显示在`职位`下拉菜单中供用户选择的数组
     *
     * isLoading: 设置选择器的加载状态
     * @type {{
     *   'array': SelectorData[],
     *   'isLoading': Boolean,
     * }}
     */
    'positionSelector': {
      'default' () {
        return {
          'array': [],
          'isLoading': false,
        }
      },
      'type': Object,
    },
    /**
     * 角色选择器
     *
     * array: 用于显示在`拥有角色`下拉菜单中供用户选择的数组
     *
     * isLoading: 设置选择器的加载状态
     * @type {{
     *   'array': SelectorData[],
     *   'isLoading': Boolean,
     * }}
     */
    'roleSelector': {
      'default' () {
        return {
          'array': [],
          'isLoading': false,
        }
      },
      'type': Object,
    },
  },

  'data' () {
    return {
      /**
       * 内部的表单数据，真正用于展示的数据
       * @type {Model}
       */
      'innerModel': {
        'roleList': [],
      },
      /**
       * 表单验证规则
       */
      'rules': {
        'code': [
          {
            'message': '请输入工号',
            'required': true,
            'trigger': 'change',
          },
        ],
        'departmentId': [
          {
            'message': '请选择一个职位',
            'required': true,
            'trigger': 'change',
          },
        ],
        'email': [
          {
            'message': '请输入电子邮箱',
            'required': true,
            'trigger': 'change',
          },
          {
            'message': '电子邮箱格式错误',
            'type': 'email',
          },
        ],
        'name': [
          {
            'message': '请输入用户名',
            'required': true,
            'trigger': 'change',
          },
        ],
        'password': [
          {
            'message': '请输入密码',
            'required': true,
            'trigger': 'change',
          },
          {
            'message': '请输入密码',
            'required': true,
            'trigger': 'change',
          },
          {
            'message': '密码的长度不能少于6位（密码由6-20位字母和数字组成）',
            'min': 6,
            'trigger': 'change',
          },
          {
            'max': 20,
            'message': '密码的长度不能多于20位（密码由6-20位字母和数字组成）',
            'trigger': 'change',
          },
          {
            'trigger': 'change',
            'validator' (_, value, callback) {
              if ((/^\D+$/u).test(value)) {
                callback(new Error('密码须包含数字（密码由6-20位字母和数字组成）'))
                return
              }
              if ((/^[^a-zA-Z]+$/u).test(value)) {
                callback(new Error('密码须包含字母（密码由6-20位字母和数字组成）'))
                return
              }
              callback()
            },
          },
        ],
        'positionId': [
          {
            'message': '请选择一个职位',
            'required': true,
            'trigger': 'change',
          },
        ],
        'roleList': [
          {
            'message': '请选择至少一个角色',
            'required': true,
            'trigger': 'change',
          },
        ],
        'sex': [
          {
            'message': '请选择一个性别',
            'required': true,
            'trigger': 'change',
          },
        ],
        'tel': [
          {
            'message': '请输入电话',
            'required': true,
            'trigger': 'change',
          },
        ],
      },
    }
  },

  'computed': {
    /**
     * 被选择的角色组成的数组
     *
     * 由于角色是可以多选的，并且选择的组件绑定的数据结构和需要传给后端的数据结构不一样，所以需要进行转换
     */
    'selectedRoleArray': {
      /**
       * @return {String[]} 角色的`id`组成的数组
       */
      'get' () {
        return this.innerModel.roleList.map(({
          id,
        }) => {
          return id
        })
      },
      /**
       * @param {String[]} newArray 新选择的角色的`id`组成的数组
       * @return {Role[]} 角色对象组成的数组
       */
      'set' (newArray) {
        this.innerModel.roleList = newArray.map((roleId) => {
          return {
            'id': roleId,
          }
        })
      },
    },
  },

  'methods': {
    /**
     * 处理`用户数据表单`的对话框的关闭按钮和取消按钮点击事件
     */
    'handleClose' () {
      this.$emit('update:isVisible', false)
    },
    /**
     * 处理`用户数据表单`的对话框的关闭动画结束事件
     */
    'handleClosed' () {
      this.innerModel = {
        'roleList': [],
      }
      this.$refs.formRef.resetFields()
    },
    /**
     * 处理`部门选择器`的下拉菜单显示状态修改事件
     * @param {Boolean} isVisible 是否显示下拉菜单
     */
    'handleDepartmentSelectorVisibleChange' (isVisible) {
      if (!isVisible) {
        return
      }
      this.$emit('department-selector-show')
    },
    /**
     * 处理`职位选择器`的下拉菜单显示状态修改事件
     * @param {Boolean} isVisible 是否显示下拉菜单
     */
    'handlePositionSelectorVisibleChange' (isVisible) {
      if (!isVisible) {
        return
      }
      this.$emit('position-selector-show')
    },
    /**
     * 处理`角色选择器`的下拉菜单显示状态修改事件
     * @param {Boolean} isVisible 是否显示下拉菜单
     */
    'handleRoleSelectorVisibleChange' (isVisible) {
      if (!isVisible) {
        return
      }
      this.$emit('role-selector-show')
    },
    /**
     * 处理`提交`按钮的点击事件
     */
    'handleSubmit' () {
      this.$refs.formRef.validate((isValid) => {
        if (!isValid) {
          return
        }
        this.$emit('submit', this.innerModel)
      })
    },
    /**
     * 将内部的表单数据和父组件传入的表单数据参数同步
     *
     * 要注意深拷贝`角色数组`
     */
    'setInnerModel' () {
      this.innerModel = {
        'roleList': [...this.model.roleList],
        ...this.model,
      }
      this.$refs.formRef.resetFields()
    },
  },
}
</script>

<style scoped lang="scss">
.select {
  width: 100%;
}

.date-picker {
  width: 100%;
}
</style>
